﻿using System;
using System.Web.Script.Serialization;
using System.Web.UI;
using System.Web.UI.WebControls;

using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.datatype;
using umbraco.interfaces;

namespace Our.Umbraco.DataType.Bitly
{
	/// <summary>
	/// The PreValue Editor for the bit.ly data-type.
	/// </summary>
	public class BitlyPrevalueEditor : Control, IDataPrevalue
	{
		/// <summary>
		/// The underlying base data-type.
		/// </summary>
		private readonly BaseDataType m_DataType;

		/// <summary>
		/// An object to temporarily lock writing to the database.
		/// </summary>
		private static readonly object m_Locker = new object();

		/// <summary>
		/// The TextBox control for the bit.ly username.
		/// </summary>
		private TextBox BitlyUsername;
		
		/// <summary>
		/// The TextBox control for the bit.ly API key.
		/// </summary>
		private TextBox BitlyApiKey;
		
		/// <summary>
		/// The CheckBox control to enable auto-generated bit.ly URLs on publish.
		/// </summary>
		private CheckBox AutoGenerate;

		/// <summary>
		/// Initializes a new instance of the <see cref="BitlyPrevalueEditor"/> class.
		/// </summary>
		/// <param name="dataType">Type of the data.</param>
		public BitlyPrevalueEditor(BaseDataType dataType)
		{
			this.m_DataType = dataType;
		}

		/// <summary>
		/// Adds the prevalue row.
		/// </summary>
		/// <param name="writer">The writer.</param>
		/// <param name="label">The label.</param>
		/// <param name="controls">The controls.</param>
		private void AddPrevalueRow(HtmlTextWriter writer, string label, params Control[] controls)
		{
			writer.AddAttribute(HtmlTextWriterAttribute.Class, "propertyItem");
			writer.RenderBeginTag(HtmlTextWriterTag.Div); // start 'propertyItem'

			writer.AddAttribute(HtmlTextWriterAttribute.Class, "propertyItemheader");
			writer.RenderBeginTag(HtmlTextWriterTag.Div); // start 'propertyItemheader'

			Label lbl = new Label() { Text = label };
			lbl.RenderControl(writer);

			writer.RenderEndTag(); // end 'propertyItemheader'

			foreach (Control control in controls)
			{
				control.RenderControl(writer);
			}

			writer.Write("<br style='clear: both'/>");

			writer.RenderEndTag(); // end 'propertyItem'
		}

		/// <summary>
		/// Gets the editor.
		/// </summary>
		/// <value>The editor.</value>
		public Control Editor
		{
			get 
			{
				return this; 
			}
		}

		/// <summary>
		/// Gets the PreValue options for the data-type.
		/// </summary>
		/// <returns>
		/// Returns the options for the PreValue Editor
		/// </returns>
		public BitlyOptions GetPreValueOptions()
		{
			var prevalues = PreValues.GetPreValues(this.m_DataType.DataTypeDefinitionId);
			if (prevalues.Count > 0)
			{
				var prevalue = (PreValue)prevalues[0];
				if (!String.IsNullOrEmpty(prevalue.Value))
				{
					try
					{
						// deserialize the options
						var serializer = new JavaScriptSerializer();

						// return the options
						return serializer.Deserialize<BitlyOptions>(prevalue.Value);
					}
					catch (Exception ex)
					{
						Log.Add(LogTypes.Error, this.m_DataType.DataTypeDefinitionId, string.Concat("Bit.ly Prevalue Editor: Execption thrown: ", ex.Message));
					}
				}
			}

			// if all else fails, return default options
			return new BitlyOptions(true);
		}

		/// <summary>
		/// Saves the data-type PreValue options.
		/// </summary>
		public void Save()
		{
			// validate the bit.ly username & API key!  ... http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/v3/validate
			
			// set the database-type for the data-type.
			this.m_DataType.DBType = DBTypes.Nvarchar;

			// set the options
			var options = new BitlyOptions()
			{
				BitlyUsername = this.BitlyUsername.Text,
				BitlyApiKey = this.BitlyApiKey.Text,
				AutoGenerate = this.AutoGenerate.Checked
			};

			// serialize the options into JSON
			var serializer = new JavaScriptSerializer();
			var json = serializer.Serialize(options);

			lock (m_Locker)
			{
				var prevalues = PreValues.GetPreValues(this.m_DataType.DataTypeDefinitionId);
				if (prevalues.Count > 0)
				{
					PreValue prevalue = (PreValue)prevalues[0];

					// update
					prevalue.Value = json;
					prevalue.Save();
				}
				else
				{
					// insert
					PreValue.MakeNew(this.m_DataType.DataTypeDefinitionId, json);
				}
			}
		}

		/// <summary>
		/// Raises the <see cref="E:System.Web.UI.Control.Init"/> event.
		/// </summary>
		/// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);
			this.EnsureChildControls();
		}

		/// <summary>
		/// Creates child controls for this control
		/// </summary>
		protected override void CreateChildControls()
		{
			base.CreateChildControls();

			// set-up child controls
			this.BitlyUsername = new TextBox() { ID = "txtBitlyUsername", CssClass = "umbEditorTextField" };
			this.BitlyApiKey = new TextBox() { ID = "txtBitlyApiKey", CssClass = "umbEditorTextField" };
			this.AutoGenerate = new CheckBox() { ID = "cbBitlyAutoGenerate", CssClass = "" };

			// add the child controls
			this.Controls.Add(this.BitlyUsername);
			this.Controls.Add(this.BitlyApiKey);
			this.Controls.Add(this.AutoGenerate);
		}

		/// <summary>
		/// Raises the <see cref="E:System.Web.UI.Control.Load"/> event.
		/// </summary>
		/// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);

			// get PreValues, load them into the controls.
			var options = this.GetPreValueOptions();

			// if the options are null, then load the defaults
			if (options == null)
			{
				options = new BitlyOptions(true);
			}

			// set the values
			this.BitlyUsername.Text = options.BitlyUsername;
			this.BitlyApiKey.Text = options.BitlyApiKey;
			this.AutoGenerate.Checked = options.AutoGenerate;
		}

		/// <summary>
		/// Sends server control content to a provided <see cref="T:System.Web.UI.HtmlTextWriter"/> object, which writes the content to be rendered on the client.
		/// </summary>
		/// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the server control content.</param>
		protected override void Render(HtmlTextWriter writer)
		{
			writer.Write("<div class='propertyItem'><p>Please enter your Bit.ly API details below, you can get these from your Bit.ly Account page: <a href='http://bit.ly/account/' target='_blank' rel='external'>http://bit.ly/account/</a> (opens in a new window)</p></div>");

			this.AddPrevalueRow(writer, "Bit.ly Username", this.BitlyUsername);
			this.AddPrevalueRow(writer, "Bit.ly API Key", this.BitlyApiKey);
			this.AddPrevalueRow(writer, "Auto Generate on Publish?", this.AutoGenerate);
		}
	}
}
